#pragma once

#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <winnt.h>
#include <intsafe.h>

#ifndef USE_LIBC
#pragma comment(linker,"/nodefaultlib:msvcrt.lib")
#pragma comment(linker,"/nodefaultlib:msvcrtd.lib")
#pragma comment(linker,"/nodefaultlib:libc.lib")
#pragma comment(linker,"/nodefaultlib:libcd.lib")
#pragma comment(linker,"/nodefaultlib:libcpmt.lib")
#pragma comment(linker,"/nodefaultlib:msvcprt.lib")
#pragma comment(linker,"/nodefaultlib:libcpmtd.lib")
#pragma comment(linker,"/nodefaultlib:msvcprtd.lib")
#endif

#ifdef USE_SYS_LIBC
#pragma comment(lib, "ntdllp.lib" )
#endif

#ifdef USE_SYS_MSVCRT
#ifdef _X86_
#pragma comment(lib, "msvcrt_x86.lib" )
#else
#pragma comment(lib, "msvcrt_x64.lib" )
#endif
#endif

#pragma comment(lib, "Kernel32.lib" )
#pragma comment(lib, "User32.lib" )
#pragma comment(lib, "advapi32.lib" )
#pragma comment( lib, "ntdll.lib" )

extern "C" void * __cdecl _alloca(_In_ size_t _Size);
#ifdef NTLIB_EXPORT
#define NTLIBAPI __declspec(dllexport)
#elif NTLIB_IMPORT
#define NTLIBAPI __declspec(dllimport)
#else
#define NTLIBAPI inline
#endif

#ifdef __cplusplus
namespace ntdll{
    extern "C" {
#endif
        typedef long NTSTATUS, *PNTSTATUS;
        typedef enum  {
            SystemBasicInformation, // 0 Y N
            SystemProcessorInformation, // 1 Y N
            SystemPerformanceInformation, // 2 Y N
            SystemTimeOfDayInformation, // 3 Y N
            SystemNotImplemented1, // 4 Y N
            SystemProcessesAndThreadsInformation, // 5 Y N
            SystemCallCounts, // 6 Y N
        } SYSTEM_INFORMATION_CLASS;
        typedef struct _UNICODE_STRING {
            USHORT Length;
            USHORT MaximumLength;
            PWSTR  Buffer;
        } UNICODE_STRING,*PUNICODE_STRING;
        typedef LONG KPRIORITY;
        typedef struct _SYSTEM_PROCESS_INFORMATION
        {
             ULONG NextEntryOffset;
             ULONG NumberOfThreads;
             LARGE_INTEGER WorkingSetPrivateSize; // since VISTA
             ULONG HardFaultCount; // since WIN7
             ULONG NumberOfThreadsHighWatermark; // since WIN7
             ULONGLONG CycleTime; // since WIN7
             LARGE_INTEGER CreateTime;
             LARGE_INTEGER UserTime;
             LARGE_INTEGER KernelTime;
             UNICODE_STRING ImageName;
             KPRIORITY BasePriority;
             HANDLE UniqueProcessId;
             HANDLE InheritedFromUniqueProcessId;
             ULONG HandleCount;
             ULONG SessionId;
             ULONG_PTR UniqueProcessKey; // since VISTA (requires SystemExtendedProcessInformation)
             SIZE_T PeakVirtualSize;
             SIZE_T VirtualSize;
             ULONG PageFaultCount;
             SIZE_T PeakWorkingSetSize;
             SIZE_T WorkingSetSize;
             SIZE_T QuotaPeakPagedPoolUsage;
             SIZE_T QuotaPagedPoolUsage;
             SIZE_T QuotaPeakNonPagedPoolUsage;
             SIZE_T QuotaNonPagedPoolUsage;
             SIZE_T PagefileUsage;
             SIZE_T PeakPagefileUsage;
             SIZE_T PrivatePageCount;
             LARGE_INTEGER ReadOperationCount;
             LARGE_INTEGER WriteOperationCount;
             LARGE_INTEGER OtherOperationCount;
             LARGE_INTEGER ReadTransferCount;
             LARGE_INTEGER WriteTransferCount;
             LARGE_INTEGER OtherTransferCount;
        } SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;

        NTSYSAPI NTSTATUS WINAPI ZwQuerySystemInformation(
            SYSTEM_INFORMATION_CLASS SystemInformationClass,
            PVOID SystemInformation,
            ULONG SystemInformationLength,
            PULONG ReturnLength
            );
        typedef enum _PROCESSINFOCLASS {
            ProcessBasicInformation, // 0 Y N
            ProcessQuotaLimits, // 1 Y Y
            ProcessIoCounters, // 2 Y N
            ProcessVmCounters, // 3 Y N
            ProcessTimes, // 4 Y N
            ProcessBasePriority, // 5 N Y
            ProcessRaisePriority,
            ProcessDebugPort,
            ProcessExceptionPort,
            ProcessAccessToken,
            ProcessLdtInformation,
            ProcessLdtSize,
            ProcessDefaultHardErrorMode,
            ProcessIoPortHandlers,          // Note: this is kernel mode only
            ProcessPooledUsageAndLimits,
            ProcessWorkingSetWatch,
            ProcessUserModeIOPL,
            ProcessEnableAlignmentFaultFixup,
            ProcessPriorityClass,
            ProcessWx86Information,
            ProcessHandleCount,
            ProcessAffinityMask,
            ProcessPriorityBoost,
            ProcessDeviceMap,
            ProcessSessionInformation,
            ProcessForegroundInformation,
            ProcessWow64Information,
            ProcessImageFileName,
            ProcessLUIDDeviceMapsEnabled,
            ProcessBreakOnTermination,
            ProcessDebugObjectHandle,
            ProcessDebugFlags,
            ProcessHandleTracing,
            ProcessIoPriority,
            ProcessExecuteFlags,
            ProcessResourceManagement,
            ProcessCookie,
            ProcessImageInformation,
            MaxProcessInfoClass             // MaxProcessInfoClass should always be the last enum
        }PROCESSINFOCLASS;
        typedef struct _PROCESS_BASIC_INFORMATION { // Information Class 0
            DWORD ExitStatus;
            PVOID PebBaseAddress;
            KAFFINITY AffinityMask;
            DWORD BasePriority;
            ULONG UniqueProcessId;
            ULONG InheritedFromUniqueProcessId;
        } PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION;
        NTSYSAPI DWORD WINAPI ZwQueryInformationProcess(
            IN HANDLE ProcessHandle,
            IN PROCESSINFOCLASS ProcessInformationClass,
            OUT PVOID ProcessInformation,
            IN ULONG ProcessInformationLength,
            OUT PULONG ReturnLength OPTIONAL
            );
        typedef NTSYSAPI DWORD (WINAPI *ZwQueryInformationProcess_t)(
            IN HANDLE ProcessHandle,
            IN PROCESSINFOCLASS ProcessInformationClass,
            OUT PVOID ProcessInformation,
            IN ULONG ProcessInformationLength,
            OUT PULONG ReturnLength OPTIONAL
            );
        typedef struct _MIB_TCPROW_OWNER_PID {
            DWORD dwState;
            DWORD dwLocalAddr;
            DWORD dwLocalPort;
            DWORD dwRemoteAddr;
            DWORD dwRemotePort;
            DWORD dwOwningPid;
        } MIB_TCPROW_OWNER_PID, *PMIB_TCPROW_OWNER_PID;
        typedef struct {
            DWORD dwNumEntries;
            MIB_TCPROW_OWNER_PID table[1];
        } MIB_TCPTABLE_OWNER_PID,  *PMIB_TCPTABLE_OWNER_PID;
        typedef enum  {
            TCP_TABLE_BASIC_LISTENER,
            TCP_TABLE_BASIC_CONNECTIONS,
            TCP_TABLE_BASIC_ALL,
            TCP_TABLE_OWNER_PID_LISTENER,
            TCP_TABLE_OWNER_PID_CONNECTIONS,
            TCP_TABLE_OWNER_PID_ALL,
            TCP_TABLE_OWNER_MODULE_LISTENER,
            TCP_TABLE_OWNER_MODULE_CONNECTIONS,
            TCP_TABLE_OWNER_MODULE_ALL 
        } TCP_TABLE_CLASS, *PTCP_TABLE_CLASS;
        WINBASEAPI DWORD WINAPI GetExtendedTcpTable(PVOID pTcpTable,PDWORD pdwSize,BOOL bOrder,ULONG ulAf,TCP_TABLE_CLASS TableClass,ULONG Reserved);
        WINBASEAPI DWORD WINAPI WTSGetActiveConsoleSessionId (VOID);
        typedef struct _CURDIR {
            UNICODE_STRING DosPath;
            HANDLE Handle;
        } CURDIR, *PCURDIR;
        typedef struct _RTL_USER_PROCESS_PARAMETERS {
            ULONG MaximumLength;
            ULONG Length;

            ULONG Flags;
            ULONG DebugFlags;

            HANDLE ConsoleHandle;
            ULONG  ConsoleFlags;
            HANDLE StandardInput;
            HANDLE StandardOutput;
            HANDLE StandardError;

            CURDIR CurrentDirectory;        // ProcessParameters
            UNICODE_STRING DllPath;         // ProcessParameters
            UNICODE_STRING ImagePathName;   // ProcessParameters
            UNICODE_STRING CommandLine;     // ProcessParameters
            PVOID Environment;              // NtAllocateVirtualMemory

            ULONG StartingX;
            ULONG StartingY;
            ULONG CountX;
            ULONG CountY;
            ULONG CountCharsX;
            ULONG CountCharsY;
            ULONG FillAttribute;

            ULONG WindowFlags;
            ULONG ShowWindowFlags;
            UNICODE_STRING WindowTitle;     // ProcessParameters
            UNICODE_STRING DesktopInfo;     // ProcessParameters
            UNICODE_STRING ShellInfo;       // ProcessParameters
            UNICODE_STRING RuntimeData;     // ProcessParameters
        } RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;

        typedef struct _CLIENT_ID {
            HANDLE UniqueProcess;
            HANDLE UniqueThread;
        } CLIENT_ID,*PCLIENT_ID;
        typedef struct _PEB_LDR_DATA {
            ULONG Length;
            BOOLEAN Initialized;
            HANDLE SsHandle;
            LIST_ENTRY InLoadOrderModuleList;
            LIST_ENTRY InMemoryOrderModuleList;
            LIST_ENTRY InInitializationOrderModuleList;
        } PEB_LDR_DATA, *PPEB_LDR_DATA;
        typedef struct _LDR_DATA_TABLE_ENTRY {
            LIST_ENTRY InLoadOrderLinks;
            LIST_ENTRY InMemoryOrderLinks;
            LIST_ENTRY InInitializationOrderLinks;
            PVOID DllBase;
            PVOID EntryPoint;
            ULONG SizeOfImage;
            UNICODE_STRING FullDllName;
            UNICODE_STRING BaseDllName;
            ULONG Flags;
            USHORT LoadCount;
            USHORT TlsIndex;
            union {
                LIST_ENTRY HashLinks;
                struct {
                    PVOID SectionPointer;
                    ULONG CheckSum;
                };
            };
            ULONG   TimeDateStamp;
        } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
        typedef struct _PEB {
            BOOLEAN InheritedAddressSpace;      // These four fields cannot change unless the
            BOOLEAN ReadImageFileExecOptions;   //
            BOOLEAN BeingDebugged;              //
            BOOLEAN SpareBool;                  //
            HANDLE Mutant;                      // INITIAL_PEB structure is also updated.

            PVOID ImageBaseAddress;
            PPEB_LDR_DATA Ldr;
            struct _RTL_USER_PROCESS_PARAMETERS *ProcessParameters;
        } PEB,*PPEB;

        typedef struct __TEB {
            NT_TIB NtTib;
            PVOID  EnvironmentPointer;
            CLIENT_ID ClientId;
            PVOID ActiveRpcHandle;
            PVOID ThreadLocalStoragePointer;
            PPEB ProcessEnvironmentBlock;
            ULONG LastErrorValue;
            ULONG CountOfOwnedCriticalSections;
            PVOID CsrClientThread;
            PVOID Win32ThreadInfo;
        } TEB,*PTEB;

        NTSYSAPI NTSTATUS WINAPI ZwQuerySystemInformation(
            IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
            IN OUT PVOID SystemInformation,
            IN ULONG SystemInformationLength,
            OUT PULONG ReturnLength OPTIONAL
            );
        typedef struct _KSYSTEM_TIME {
            ULONG LowPart;
            LONG High1Time;
            LONG High2Time;
        } KSYSTEM_TIME, *PKSYSTEM_TIME;
        typedef enum _NT_PRODUCT_TYPE {
            NtProductWinNt = 1,
            NtProductLanManNt,
            NtProductServer
        } NT_PRODUCT_TYPE, *PNT_PRODUCT_TYPE;
        typedef enum _ALTERNATIVE_ARCHITECTURE_TYPE {
            StandardDesign,                 // None == 0 == standard design
            NEC98x86,                       // NEC PC98xx series on X86
            EndAlternatives                 // past end of known alternatives
        } ALTERNATIVE_ARCHITECTURE_TYPE;
        typedef struct _KUSER_SHARED_DATA
        {
            ULONG TickCountLowDeprecated;
            ULONG TickCountMultiplier;
            KSYSTEM_TIME InterruptTime;
            KSYSTEM_TIME SystemTime;
            KSYSTEM_TIME TimeZoneBias;
            WORD ImageNumberLow;
            WORD ImageNumberHigh;
            WCHAR NtSystemRoot[260];
            ULONG MaxStackTraceDepth;
            ULONG CryptoExponent;
            ULONG TimeZoneId;
            ULONG LargePageMinimum;
            ULONG Reserved2[7];
            NT_PRODUCT_TYPE NtProductType;
            UCHAR ProductTypeIsValid;
            ULONG NtMajorVersion;
            ULONG NtMinorVersion;
            UCHAR ProcessorFeatures[64];
            ULONG Reserved1;
            ULONG Reserved3;
            ULONG TimeSlip;
            ALTERNATIVE_ARCHITECTURE_TYPE AlternativeArchitecture;
            LARGE_INTEGER SystemExpirationDate;
            ULONG SuiteMask;
            UCHAR KdDebuggerEnabled;
            UCHAR NXSupportPolicy;
            ULONG ActiveConsoleId;
            ULONG DismountCount;
            ULONG ComPlusPackage;
            ULONG LastSystemRITEventTickCount;
            ULONG NumberOfPhysicalPages;
            UCHAR SafeBootMode;
            ULONG SharedDataFlags;
            ULONG DbgErrorPortPresent: 1;
            ULONG DbgElevationEnabled: 1;
            ULONG DbgVirtEnabled: 1;
            ULONG DbgInstallerDetectEnabled: 1;
            ULONG SystemDllRelocated: 1;
            ULONG SpareBits: 27;
            UINT64 TestRetInstruction;
            ULONG SystemCall;
            ULONG SystemCallReturn;
            UINT64 SystemCallPad[3];
            union
            {
                KSYSTEM_TIME TickCount;
                UINT64 TickCountQuad;
            };
            ULONG Cookie;
            INT64 ConsoleSessionForegroundProcessId;
            ULONG Wow64SharedInformation[16];
            WORD UserModeGlobalLogger[8];
            ULONG HeapTracingPid[2];
            ULONG CritSecTracingPid[2];
            ULONG ImageFileExecutionOptions;
            union
            {
                UINT64 AffinityPad;
                ULONG ActiveProcessorAffinity;
            };
            UINT64 InterruptTimeBias;
        } KUSER_SHARED_DATA, *PKUSER_SHARED_DATA;
#define MM_SHARED_USER_DATA_VA      0x7FFE0000

#define USER_SHARED_DATA ((KUSER_SHARED_DATA * const)MM_SHARED_USER_DATA_VA)

        BOOL WINAPI GetSystemTimes(
            LPFILETIME lpIdleTime,
            LPFILETIME lpKernelTime,
            LPFILETIME lpUserTime
            );
        typedef struct _SYSTEM_PERFORMANCE_INFORMATION {
            __int64 IdleProcessTime;
            __int64 IoReadTransferCount;
            __int64 IoWriteTransferCount;
            __int64 IoOtherTransferCount;
            ULONG IoReadOperationCount;
            ULONG IoWriteOperationCount;
            ULONG IoOtherOperationCount;
            ULONG AvailablePages;
            ULONG CommittedPages;
            ULONG CommitLimit;
            ULONG PeakCommitment;
            ULONG PageFaultCount;
            ULONG CopyOnWriteCount;
            ULONG TransitionCount;
            ULONG CacheTransitionCount;
            ULONG DemandZeroCount;
            ULONG PageReadCount;
            ULONG PageReadIoCount;
            ULONG CacheReadCount;
            ULONG CacheIoCount;
            ULONG DirtyPagesWriteCount;
            ULONG DirtyWriteIoCount;
            ULONG MappedPagesWriteCount;
            ULONG MappedWriteIoCount;
            ULONG PagedPoolPages;
            ULONG NonPagedPoolPages;
            ULONG PagedPoolAllocs;
            ULONG PagedPoolFrees;
            ULONG NonPagedPoolAllocs;
            ULONG NonPagedPoolFrees;
            ULONG FreeSystemPtes;
            ULONG ResidentSystemCodePage;
            ULONG TotalSystemDriverPages;
            ULONG TotalSystemCodePages;
            ULONG NonPagedPoolLookasideHits;
            ULONG PagedPoolLookasideHits;
            ULONG Spare3Count;
            ULONG ResidentSystemCachePage;
            ULONG ResidentPagedPoolPage;
            ULONG ResidentSystemDriverPage;
            ULONG CcFastReadNoWait;
            ULONG CcFastReadWait;
            ULONG CcFastReadResourceMiss;
            ULONG CcFastReadNotPossible;
            ULONG CcFastMdlReadNoWait;
            ULONG CcFastMdlReadWait;
            ULONG CcFastMdlReadResourceMiss;
            ULONG CcFastMdlReadNotPossible;
            ULONG CcMapDataNoWait;
            ULONG CcMapDataWait;
            ULONG CcMapDataNoWaitMiss;
            ULONG CcMapDataWaitMiss;
            ULONG CcPinMappedDataCount;
            ULONG CcPinReadNoWait;
            ULONG CcPinReadWait;
            ULONG CcPinReadNoWaitMiss;
            ULONG CcPinReadWaitMiss;
            ULONG CcCopyReadNoWait;
            ULONG CcCopyReadWait;
            ULONG CcCopyReadNoWaitMiss;
            ULONG CcCopyReadWaitMiss;
            ULONG CcMdlReadNoWait;
            ULONG CcMdlReadWait;
            ULONG CcMdlReadNoWaitMiss;
            ULONG CcMdlReadWaitMiss;
            ULONG CcReadAheadIos;
            ULONG CcLazyWriteIos;
            ULONG CcLazyWritePages;
            ULONG CcDataFlushes;
            ULONG CcDataPages;
            ULONG ContextSwitches;
            ULONG FirstLevelTbFills;
            ULONG SecondLevelTbFills;
            ULONG SystemCalls;
        } SYSTEM_PERFORMANCE_INFORMATION, *PSYSTEM_PERFORMANCE_INFORMATION;
        typedef struct _SYSTEM_PERFORMANCE_INFORMATION_P {
            BYTE Reserved1[312];
        } SYSTEM_PERFORMANCE_INFORMATION_P;
        typedef struct _OBJECT_ATTRIBUTES {
            ULONG Length;
            HANDLE RootDirectory;
            PUNICODE_STRING ObjectName;
            ULONG Attributes;
            PVOID SecurityDescriptor;        // Points to type SECURITY_DESCRIPTOR
            PVOID SecurityQualityOfService;  // Points to type SECURITY_QUALITY_OF_SERVICE
        } OBJECT_ATTRIBUTES,*POBJECT_ATTRIBUTES;
        NTSYSAPI NTSTATUS WINAPI ZwOpenProcess(
            OUT PHANDLE ProcessHandle,
            IN ACCESS_MASK DesiredAccess,
            IN POBJECT_ATTRIBUTES ObjectAttributes,
            IN PCLIENT_ID ClientId OPTIONAL
            );
        NTSYSAPI VOID WINAPI RtlInitUnicodeString(
            IN OUT PUNICODE_STRING  DestinationString,
            IN PCWSTR  SourceString
            );
        NTSYSAPI VOID WINAPI
            InitializeObjectAttributes(
            OUT POBJECT_ATTRIBUTES  InitializedAttributes,
            IN PUNICODE_STRING  ObjectName,
            IN ULONG  Attributes,
            IN HANDLE  RootDirectory,
            IN PSECURITY_DESCRIPTOR  SecurityDescriptor
            );
#define OBJ_INHERIT             0x00000002L
#define OBJ_PERMANENT           0x00000010L
#define OBJ_EXCLUSIVE           0x00000020L
#define OBJ_CASE_INSENSITIVE    0x00000040L
#define OBJ_OPENIF              0x00000080L
#define OBJ_OPENLINK            0x00000100L
#define OBJ_KERNEL_HANDLE       0x00000200L
#define OBJ_FORCE_ACCESS_CHECK  0x00000400L
#define OBJ_VALID_ATTRIBUTES    0x000007F2L
#define STATUS_OBJECT_NAME_EXISTS        ((NTSTATUS)0x40000000L)
        //SYSDBG_COMMAND
        typedef enum _SYSDBG_COMMAND {
            SysDbgQueryModuleInformation,
            SysDbgQueryTraceInformation,
            SysDbgSetTracepoint,
            SysDbgSetSpecialCall,
            SysDbgClearSpecialCalls,
            SysDbgQuerySpecialCalls,
            SysDbgBreakPoint,
            SysDbgQueryVersion,
            SysDbgReadVirtual,
            SysDbgWriteVirtual,
            SysDbgReadPhysical,
            SysDbgWritePhysical,
            SysDbgReadControlSpace,
            SysDbgWriteControlSpace,
            SysDbgReadIoSpace,
            SysDbgWriteIoSpace,
            SysDbgReadMsr,
            SysDbgWriteMsr,
            SysDbgReadBusData,
            SysDbgWriteBusData,
            SysDbgCheckLowMemory,
            SysDbgEnableKernelDebugger,
            SysDbgDisableKernelDebugger,
            SysDbgGetAutoKdEnable,
            SysDbgSetAutoKdEnable,
            SysDbgGetPrintBufferSize,
            SysDbgSetPrintBufferSize,
            SysDbgGetKdUmExceptionEnable,
            SysDbgSetKdUmExceptionEnable,
            SysDbgGetTriageDump,
            SysDbgGetKdBlockEnable,
            SysDbgSetKdBlockEnable,
        } SYSDBG_COMMAND, *PSYSDBG_COMMAND;

        //SYSDBG_VIRTUAL
        typedef struct _SYSDBG_VIRTUAL {
            PVOID Address;
            PVOID Buffer;
            ULONG Request;
        } SYSDBG_VIRTUAL, *PSYSDBG_VIRTUAL;
        typedef struct _PROCESS_ACCESS_TOKEN {
            HANDLE Token;
            HANDLE Thread;
        } PROCESS_ACCESS_TOKEN, *PPROCESS_ACCESS_TOKEN;
        NTSYSAPI NTSTATUS WINAPI
            NtSystemDebugControl(
            IN SYSDBG_COMMAND Command,
            IN PVOID InputBuffer  OPTIONAL, 
            IN ULONG InputBufferLength, 
            OUT PVOID OutputBuffer  OPTIONAL, 
            IN ULONG OutputBufferLength, 
            OUT PULONG ReturnLength  OPTIONAL 
            );
        PVOID
            RtlImageDirectoryEntryToData (
            IN PVOID Base,
            IN BOOLEAN MappedAsImage,
            IN USHORT DirectoryEntry,
            OUT PULONG Size
            );
        NTSYSAPI NTSTATUS WINAPI NtQuerySystemTime(__int64 *SystemTime);
        NTSYSAPI NTSTATUS WINAPI NtQueryTimerResolution(OUT PULONG MinimumResolution, OUT PULONG MaximumResolution, OUT PULONG CurrentResolution ); 
        NTSYSAPI NTSTATUS WINAPI NtSetTimerResolution(IN ULONG DesiredResolution, IN BOOLEAN SetResolution, OUT PULONG CurrentResolution );
        NTSYSAPI NTSTATUS WINAPI RtlCreateUserThread(IN HANDLE ProcessHandle, IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL, IN BOOLEAN CreateSuspended, IN ULONG StackZeroBits, IN OUT PULONG StackReserved, IN OUT PULONG StackCommit, IN PVOID StartAddress, IN PVOID StartParameter OPTIONAL, OUT PHANDLE ThreadHandle, OUT PCLIENT_ID ClientID );
        typedef struct _NtCreateThreadExBuffer
        {
            ULONG Size;
            ULONG Unknown1;
            ULONG Unknown2;
            PULONG Unknown3;
            ULONG Unknown4;
            ULONG Unknown5;
            ULONG Unknown6;
            PULONG Unknown7;
            ULONG Unknown8;
        } NtCreateThreadExBuffer;
        NTSYSAPI NTSTATUS WINAPI NtCreateThreadEx(
            OUT PHANDLE hThread,
            IN ACCESS_MASK DesiredAccess,
            IN LPVOID ObjectAttributes,
            IN HANDLE ProcessHandle,
            IN LPTHREAD_START_ROUTINE lpStartAddress,
            IN LPVOID lpParameter,
            IN BOOL CreateSuspended,
            IN ULONG StackZeroBits,
            IN ULONG SizeOfStackCommit,
            IN ULONG SizeOfStackReserve,
            OUT LPVOID lpBytesBuffer
            );
#define DIRECTORY_QUERY                 (0x0001)
#define DIRECTORY_TRAVERSE              (0x0002)
#define DIRECTORY_CREATE_OBJECT         (0x0004)
#define DIRECTORY_CREATE_SUBDIRECTORY   (0x0008)

		NTSYSAPI NTSTATUS WINAPI NtOpenDirectoryObject(
			_Out_  PHANDLE DirectoryHandle,
			_In_   ACCESS_MASK DesiredAccess,
			_In_   POBJECT_ATTRIBUTES ObjectAttributes
			);
		NTSYSAPI NTSTATUS WINAPI NtQueryDirectoryObject(
			_In_       HANDLE DirectoryHandle,
			_Out_opt_  PVOID Buffer,
			_In_       ULONG Length,
			_In_       BOOLEAN ReturnSingleEntry,
			_In_       BOOLEAN RestartScan,
			_Inout_    PULONG Context,
			_Out_opt_  PULONG ReturnLength
			);
		typedef struct _OBJECT_DIRECTORY_INFORMATION {
			UNICODE_STRING Name;
			UNICODE_STRING TypeName;
		} OBJECT_DIRECTORY_INFORMATION, *POBJECT_DIRECTORY_INFORMATION;
        NTSYSAPI NTSTATUS WINAPI ZwUnmapViewOfSection(
            _In_      HANDLE ProcessHandle,
            _In_opt_  PVOID BaseAddress
            );
        NTSYSAPI NTSTATUS WINAPI ZwFreeVirtualMemory(
            _In_     HANDLE ProcessHandle,
            _Inout_  PVOID *BaseAddress,
            _Inout_  PSIZE_T RegionSize,
            _In_     ULONG FreeType
            );
        NTSYSAPI NTSTATUS WINAPI ZwFilterToken(
            IN HANDLE ExistingTokenHandle,
            IN ULONG Flags,
            IN PTOKEN_GROUPS SidsToDisable,
            IN PTOKEN_PRIVILEGES PrivilegesToDelete,
            IN PTOKEN_GROUPS SidsToRestricted,
            OUT PHANDLE NewTokenHandle
            );
        NTSYSAPI NTSTATUS WINAPI ZwSetInformationToken(
            IN HANDLE TokenHandle,
            IN TOKEN_INFORMATION_CLASS TokenInformationClass,
            IN PVOID TokenInformation,
            IN ULONG TokenInformationLength
            );
        NTSYSAPI NTSTATUS WINAPI
            ZwCreateToken(
            OUT PHANDLE TokenHandle,
            IN ACCESS_MASK DesiredAccess,
            IN POBJECT_ATTRIBUTES ObjectAttributes,
            IN TOKEN_TYPE Type,
            IN PLUID AuthenticationId,
            IN PLARGE_INTEGER ExpirationTime,
            IN PTOKEN_USER User,
            IN PTOKEN_GROUPS Groups,
            IN PTOKEN_PRIVILEGES Privileges,
            IN PTOKEN_OWNER Owner,
            IN PTOKEN_PRIMARY_GROUP PrimaryGroup,
            IN PTOKEN_DEFAULT_DACL DefaultDacl,
            IN PTOKEN_SOURCE Source
            );
        NTSYSAPI NTSTATUS WINAPI
            ZwSetInformationProcess(
            IN HANDLE ProcessHandle,
            IN PROCESSINFOCLASS ProcessInformationClass,
            IN PVOID ProcessInformation,
            IN ULONG ProcessInformationLength
            );
        NTSYSAPI ULONG WINAPI RtlLengthSid(
            _In_  PSID Sid
            );

#define SE_MIN_WELL_KNOWN_PRIVILEGE (2L)
#define SE_CREATE_TOKEN_PRIVILEGE (2L)
#define SE_ASSIGNPRIMARYTOKEN_PRIVILEGE (3L)
#define SE_LOCK_MEMORY_PRIVILEGE (4L)
#define SE_INCREASE_QUOTA_PRIVILEGE (5L)

#define SE_MACHINE_ACCOUNT_PRIVILEGE (6L)
#define SE_TCB_PRIVILEGE (7L)
#define SE_SECURITY_PRIVILEGE (8L)
#define SE_TAKE_OWNERSHIP_PRIVILEGE (9L)
#define SE_LOAD_DRIVER_PRIVILEGE (10L)
#define SE_SYSTEM_PROFILE_PRIVILEGE (11L)
#define SE_SYSTEMTIME_PRIVILEGE (12L)
#define SE_PROF_SINGLE_PROCESS_PRIVILEGE (13L)
#define SE_INC_BASE_PRIORITY_PRIVILEGE (14L)
#define SE_CREATE_PAGEFILE_PRIVILEGE (15L)
#define SE_CREATE_PERMANENT_PRIVILEGE (16L)
#define SE_BACKUP_PRIVILEGE (17L)
#define SE_RESTORE_PRIVILEGE (18L)
#define SE_SHUTDOWN_PRIVILEGE (19L)
#define SE_DEBUG_PRIVILEGE (20L)
#define SE_AUDIT_PRIVILEGE (21L)
#define SE_SYSTEM_ENVIRONMENT_PRIVILEGE (22L)
#define SE_CHANGE_NOTIFY_PRIVILEGE (23L)
#define SE_REMOTE_SHUTDOWN_PRIVILEGE (24L)
#define SE_UNDOCK_PRIVILEGE (25L)
#define SE_SYNC_AGENT_PRIVILEGE (26L)
#define SE_ENABLE_DELEGATION_PRIVILEGE (27L)
#define SE_MANAGE_VOLUME_PRIVILEGE (28L)
#define SE_IMPERSONATE_PRIVILEGE (29L)
#define SE_CREATE_GLOBAL_PRIVILEGE (30L)
#define SE_TRUSTED_CREDMAN_ACCESS_PRIVILEGE (31L)
#define SE_RELABEL_PRIVILEGE (32L)
#define SE_INC_WORKING_SET_PRIVILEGE (33L)
#define SE_TIME_ZONE_PRIVILEGE (34L)
#define SE_CREATE_SYMBOLIC_LINK_PRIVILEGE (35L)
#define SE_MAX_WELL_KNOWN_PRIVILEGE SE_CREATE_SYMBOLIC_LINK_PRIVILEGE

#ifndef _WIN64
        __inline PTEB __declspec(naked) NtCurrentTeb( void ) { __asm {mov eax, fs:[0x18]
        ret} }
#else
        __inline PTEB NtCurrentTeb( void ) 
        { 
            return (PTEB)::NtCurrentTeb();
        }
#endif

#ifdef __cplusplus
    }
}
#endif

#ifdef __cplusplus
namespace ntlib{
extern "C" {
using namespace ntdll;
#endif

static wchar_t	*optarg;		// global argument pointer
static int		optind; 	// global argv index
NTLIBAPI int getopt(int argc, wchar_t *argv[], wchar_t *optstring)
{
    static wchar_t *next = NULL;
    if (optind == 0)
        next = NULL;
        
    optarg = NULL;

    if (next == NULL || *next == (L'\0'))
    {
        if (optind == 0)
            optind++;

        if (optind >= argc || (argv[optind][0] != L'-' && argv[optind][0] != L'\\' && argv[optind][0] != L'/')     || argv[optind][1] == L'\0')
        {
            optarg = NULL;
            if (optind < argc)
                optarg = argv[optind];
            return -1;
        }

        if (wcscmp(argv[optind], (L"--")) == 0)
        {
            optind++;
            optarg = NULL;
            if (optind < argc)
                optarg = argv[optind];
            return -1;
        }

        next = argv[optind];
        next++;		// skip past -
        optind++;
    }

    wchar_t c = *next++;
    wchar_t *cp = wcschr(optstring, c);

    if (cp == NULL || c == (L':'))
        return (L'?');

    cp++;
    if (*cp == (L':'))
    {
        if (*next != L'\0')
        {
            optarg = next;
            next = NULL;
        }
        else if (optind < argc)
        {
            optarg = argv[optind];
            optind++;
        }
        else
        {
            return (L'?');
        }
    }

    return c;
}

static void  Parse_Cmdline (
    LPCWSTR cmdstart,
    LPWSTR*argv,
    LPWSTR lpstr,
    INT *numargs,
    INT *numbytes
)
{
    LPCWSTR p;
    WCHAR c;
    INT inquote;                    /* 1 = inside quotes */
    INT copychar;                   /* 1 = copy char to *args */
    WORD numslash;                  /* num of backslashes seen */

    *numbytes = 0;
    *numargs = 1;                   /* the program name at least */

    /* first scan the program name, copy it, and count the bytes */
    p = cmdstart;
    if (argv)
        *argv++ = lpstr;

    /* A quoted program name is handled here. The handling is much
       simpler than for other arguments. Basically, whatever lies
       between the leading double-quote and next one, or a terminal null
       character is simply accepted. Fancier handling is not required
       because the program name must be a legal NTFS/HPFS file name.
       Note that the double-quote characters are not copied, nor do they
       contribute to numbytes. */
    if (*p == TEXT('\"'))
    {
        /* scan from just past the first double-quote through the next
           double-quote, or up to a null, whichever comes first */
        while ((*(++p) != TEXT('\"')) && (*p != TEXT('\0')))
        {
            *numbytes += sizeof(WCHAR);
            if (lpstr)
                *lpstr++ = *p;
        }
        /* append the terminating null */
        *numbytes += sizeof(WCHAR);
        if (lpstr)
            *lpstr++ = TEXT('\0');

        /* if we stopped on a double-quote (usual case), skip over it */
        if (*p == TEXT('\"'))
            p++;
    }
    else
    {
        /* Not a quoted program name */
        do {
            *numbytes += sizeof(WCHAR);
            if (lpstr)
                *lpstr++ = *p;

            c = (WCHAR) *p++;

        } while (c > TEXT(' '));

        if (c == TEXT('\0'))
        {
            p--;
        }
        else
        {
            if (lpstr)
                *(lpstr - 1) = TEXT('\0');
        }
    }

    inquote = 0;

    /* loop on each argument */
    for ( ; ; )
    {
        if (*p)
        {
            while (*p == TEXT(' ') || *p == TEXT('\t'))
                ++p;
        }

        if (*p == TEXT('\0'))
            break;                  /* end of args */

        /* scan an argument */
        if (argv)
            *argv++ = lpstr;         /* store ptr to arg */
        ++*numargs;

        /* loop through scanning one argument */
        for ( ; ; )
        {
            copychar = 1;
            /* Rules: 2N backslashes + " ==> N backslashes and begin/end quote
                      2N+1 backslashes + " ==> N backslashes + literal "
                      N backslashes ==> N backslashes */
            numslash = 0;
            while (*p == TEXT('\\'))
            {
                /* count number of backslashes for use below */
                ++p;
                ++numslash;
            }
            if (*p == TEXT('\"'))
            {
                /* if 2N backslashes before, start/end quote, otherwise
                   copy literally */
                if (numslash % 2 == 0)
                {
                    if (inquote)
                        if (p[1] == TEXT('\"'))
                            p++;    /* Double quote inside quoted string */
                        else        /* skip first quote char and copy second */
                            copychar = 0;
                    else
                        copychar = 0;       /* don't copy quote */

                    inquote = !inquote;
                }
                numslash /= 2;          /* divide numslash by two */
            }

            /* copy slashes */
            while (numslash--)
            {
                if (lpstr)
                    *lpstr++ = TEXT('\\');
                *numbytes += sizeof(WCHAR);
            }

            /* if at end of arg, break loop */
            if (*p == TEXT('\0') || (!inquote && (*p == TEXT(' ') || *p == TEXT('\t'))))
                break;

            /* copy character into argument */
            if (copychar)
            {
                if (lpstr)
                        *lpstr++ = *p;
                *numbytes += sizeof(WCHAR);
            }
            ++p;
        }

        /* null-terminate the argument */

        if (lpstr)
            *lpstr++ = TEXT('\0');         /* terminate string */
        *numbytes += sizeof(WCHAR);
    }

}

NTLIBAPI wchar_t  **  argvw(wchar_t* lpCmdLine, int*pNumArgs)
{
    LPWSTR*argv_U;
    LPCWSTR  cmdstart;                 /* start of command line to parse */
    INT     numbytes;

    if (pNumArgs == NULL) {
        SetLastError(ERROR_INVALID_PARAMETER);
        return NULL;
    }

    /* if there's no command line at all (won't happen from cmd.exe, but
       possibly another program), then we use pgmname as the command line
       to parse, so that argv[0] is initialized to the program name */
    if (lpCmdLine == 0 || *lpCmdLine == L'\0')
        return NULL;

    cmdstart = lpCmdLine;

    /* first find out how much space is needed to store args */
    Parse_Cmdline (cmdstart, NULL, NULL, pNumArgs, &numbytes);

    /* allocate space for argv[] vector and strings */
    argv_U = (LPWSTR*) HeapAlloc(GetProcessHeap(),HEAP_NO_SERIALIZE,(*pNumArgs+1) * sizeof(LPWSTR) + numbytes);
    if (!argv_U) {
        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
        return (NULL);
    }

    /* store args and argv ptrs in just allocated block */
    Parse_Cmdline (cmdstart, argv_U,
                   (LPWSTR) (((LPBYTE)argv_U) + *pNumArgs * sizeof(LPWSTR)),
                   pNumArgs, &numbytes);

    return (argv_U);
}
NTLIBAPI unsigned find_process_id(wchar_t* p){
    ntdll::NTSTATUS r = 0;
    ULONG len = 0;
    PSYSTEM_PROCESS_INFORMATION sis;
    PVOID mem = 0;
    unsigned pid = 0;

    ZwQuerySystemInformation(SystemProcessesAndThreadsInformation,0,0,&len);
    len *= 2;
    sis = (PSYSTEM_PROCESS_INFORMATION)_alloca(len);
    if (!sis) return 0;
    mem = sis;
    r = ZwQuerySystemInformation(SystemProcessesAndThreadsInformation,sis,len,&len);
    if (r == 0) {
        for (;;) {
            if (sis->ImageName.Buffer) {
                if (0 == _wcsicmp(sis->ImageName.Buffer,p)) {
                    pid = (unsigned)sis->UniqueProcessId;
                    break;
                }
            }

            if (sis->NextEntryOffset == 0)
                break;
            sis = (PSYSTEM_PROCESS_INFORMATION)((PUCHAR)sis + sis->NextEntryOffset);
        }
    }
    return pid;
}
NTLIBAPI wchar_t* find_process_name(unsigned pid,wchar_t* buf,unsigned size){
    ntdll::NTSTATUS r = 0;
    ULONG len = 0;
    PSYSTEM_PROCESS_INFORMATION sis;
    PVOID mem = 0;
    wchar_t *name = 0;
    ZwQuerySystemInformation(SystemProcessesAndThreadsInformation,0,0,&len);
    len *= 2;
    sis = (PSYSTEM_PROCESS_INFORMATION)_alloca(len);
    if(!sis) return 0;
    mem = sis;
    r = ZwQuerySystemInformation(SystemProcessesAndThreadsInformation,sis,len,&len);
    if (r == 0){
        for (;;) {
            if (sis->ImageName.Buffer) {
                if (sis->UniqueProcessId == (PVOID)pid) {
                    name = sis->ImageName.Buffer;
                    break;
                }
            }

            if (sis->NextEntryOffset == 0)
                break;
            sis = (PSYSTEM_PROCESS_INFORMATION)((PUCHAR)sis + sis->NextEntryOffset);
        }
    }
    if (name && buf){
        size /= sizeof(wchar_t);
        buf[0] = 0;
        buf[size-1] = 0;
        if (size > 1)
            wcsncpy(buf,name,size-1);
    }
    return name?buf:0;
}

NTLIBAPI unsigned parent_process() {
    PROCESS_BASIC_INFORMATION ppinfo = {0};
    ULONG len = 0;
    DWORD ret = ZwQueryInformationProcess(GetCurrentProcess(),ProcessBasicInformation,&ppinfo,sizeof(ppinfo),&len);
    return ( ret == 0 ) ? ppinfo.InheritedFromUniqueProcessId : 0;

}
NTLIBAPI unsigned last_user_input() {
    LASTINPUTINFO i ={sizeof(LASTINPUTINFO),0};
    DWORD tick;
    GetLastInputInfo(&i);
    tick = GetTickCount();
    return (tick-i.dwTime)/1000;
}
NTLIBAPI void mwprintf(const wchar_t*t,...)
{
    if(!t) return;
    va_list ap;
    wchar_t buffer[256];
    va_start(ap, t);
    extern int _vsnwprintf (wchar_t *string, size_t count, const wchar_t *format,va_list ap);
    int ret = _vsnwprintf(buffer,256, t, ap);
    va_end(ap);
    DWORD r;
    WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),buffer,ret>=0?ret:256,&r,0);
}
NTLIBAPI void mprintf(const char*t,...)
{
    if(!t) return;
    va_list ap;
    char buffer[256];
    va_start(ap, t);
    extern int _vsnprintf(char *buffer,size_t count,const char *format,va_list argptr);
    int ret = _vsnprintf(buffer,256, t, ap);
    va_end(ap);
    DWORD r;
    WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),buffer,ret>=0?ret:256,&r,0);
}

typedef struct {
    char*  orig_proc;
    char*  hook_proc;
    char*  stub_proc;
    char*  juncture;
    char  stub[40];
    unsigned long oldp;
    unsigned size;
} hook_info;
#ifndef _WIN64
#pragma pack(push,1)
typedef union {
    char bytes[5];
    struct {
        char b1;
        unsigned addr;
    };
}jmp_asm;
#pragma pack(pop)
#else
#pragma pack(push,1)
typedef union {
    char bytes[12];
    struct {
        unsigned short s1;
        void* addr;
        unsigned short s2;
    };
}jmp_asm;
#pragma pack(pop)
#endif // _WIN64

// 48 b8 [ff ff ff ff ee ee ee aa] ff e0 
NTLIBAPI hook_info * hook_proc(void* const p, void * const j, void* const r,unsigned const size,hook_info * const h)
{
    if (size < sizeof(jmp_asm)|| !p|| !j || !r|| !h)
        return 0;
    __try {
        if (h->stub_proc == h->stub)
            return 0;
        BOOL ret;
        DWORD oldp;
        ret = VirtualProtect(h,sizeof(hook_info),PAGE_EXECUTE_READWRITE,&oldp);
        if (!ret) return 0;
        ret = VirtualProtect(p,size,PAGE_EXECUTE_READWRITE,&h->oldp);
        if (!ret) return 0;

        memcpy(h->stub,p,size);
        memset(p,0x90,size);
        jmp_asm* pp = (jmp_asm*)p;
#ifndef _WIN64
        pp->b1 = (char)0xe9;
        pp->addr = (char*)j - &pp->bytes[5];
#else
        pp->s1 = 0xb848;
        pp->s2 = 0xe0ff;
        pp->addr = j;
#endif
        jmp_asm* ss = (jmp_asm*) &h->stub[size];
#ifndef _WIN64
        ss->b1 = (char)0xe9;
        ss->addr = &pp->bytes[5] - &ss->bytes[5];
#else
        ss->s1 = 0xb848;
        ss->s2 = 0xe0ff;
        ss->addr = (char*)p + size;
#endif        
        FlushInstructionCache(GetCurrentProcess(),p,size);
        VirtualProtect(p,size,h->oldp,&oldp);
        h->orig_proc = (char*)p;
        h->size = size;
        h->stub_proc = h->stub;
#ifndef _WIN64
        h->juncture = &pp->bytes[5];
#else
        h->juncture = (char*)p + size;
#endif
        *(char**)r = h->stub;
    }
    __except(EXCEPTION_EXECUTE_HANDLER) {
        return 0;
    }
    return h;
}
NTLIBAPI int unhook_proc(hook_info* h) {
    __try {
        if (!h || h->orig_proc == 0) return 0;
        DWORD oldp;
        DWORD ret = 0;
        ret = VirtualProtect(h->orig_proc,h->size,PAGE_EXECUTE_READWRITE,&oldp);
        if (!ret) return 0;
        memcpy(h->orig_proc,h->stub,h->size);
        VirtualProtect(h->orig_proc,h->size,oldp,&h->oldp);
        FlushInstructionCache(GetCurrentProcess(),h->orig_proc,h->size);
        h->orig_proc = 0;
        h->stub_proc = 0;
    }
    __except(EXCEPTION_EXECUTE_HANDLER) {
        return 0;
    }
    return 1;
}
typedef unsigned long  (WINAPI *tproc_t)(void*);
NTLIBAPI unsigned long create_thread(tproc_t p, void* par) {
    DWORD tid = 0;
    CloseHandle(CreateThread(0,0,p,par,0,&tid));
    return tid;
}
NTLIBAPI int  priv_access(LPWSTR privilage,DWORD tag, HANDLE token) 
{
    LUID_AND_ATTRIBUTES attr;
    int c = 0;
    if ( token  == 0) {
        if (! OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token) )
            return 0;
        c = 1;
    }
    if (!LookupPrivilegeValueW(NULL,privilage,&attr.Luid))
    {
        c?CloseHandle(token):0;
        return 0;
    }
    TOKEN_PRIVILEGES privs;
    attr.Attributes = tag;
    privs.PrivilegeCount = 1;
    privs.Privileges[0] = attr;
    if (!AdjustTokenPrivileges(token,FALSE,&privs,NULL,NULL,NULL))
    {
        c?CloseHandle(token):0;
        return 0;
    }
    c?CloseHandle(token):0;
    return 1;
}

NTLIBAPI HANDLE NtCreateThreadExWrapper(HANDLE hHandle, LPVOID loadLibAddr, LPVOID dllPathAddr) {

    HANDLE hRemoteThread = NULL;
    NtCreateThreadExBuffer ntbuffer;
    DWORD temp1 = 0;
    DWORD temp2 = 0;

    ntbuffer.Size = sizeof(ntbuffer);
    ntbuffer.Unknown1 = 0x10003;
    ntbuffer.Unknown2 = 0x8;
    ntbuffer.Unknown3 = &temp2;
    ntbuffer.Unknown4 = 0;
    ntbuffer.Unknown5 = 0x10004;
    ntbuffer.Unknown6 = 4;
    ntbuffer.Unknown7 = &temp1;
    ntbuffer.Unknown8 = 0;


    ntdll::NTSTATUS status = NtCreateThreadEx(
        &hRemoteThread,
        0x1FFFFF,
        NULL,
        hHandle,
        (LPTHREAD_START_ROUTINE)loadLibAddr,
        dllPathAddr,
        FALSE,
        NULL,
        NULL,
        NULL,
        &ntbuffer
        );

    if (hRemoteThread == NULL) {
        return NULL;
    } else {
        return hRemoteThread;
    }

}


NTLIBAPI HANDLE RtlCreateUserThreadWrapper(HANDLE hHandle, LPVOID loadLibAddr, LPVOID dllPathAddr)
{
    /*
    Provided help
    http://syprog.blogspot.com/2012/05/createremotethread-bypass-windows.html?showComment=1338375764336#c4138436235159645886
    http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Executable%20Images/RtlCreateUserThread.html
    http://www.rohitab.com/discuss/topic/39493-using-rtlcreateuserthread/
    */


    HANDLE hRemoteThread = NULL;
    LPVOID rtlCreateUserAddr = NULL;

    CLIENT_ID cid;

    RtlCreateUserThread(
        hHandle, // ProcessHandle
        NULL, // SecurityDescriptor (OPTIONAL)
        FALSE, // CreateSuspended
        0, // StackZeroBits
        0, // StackReserved
        0, // StackCommit
        (PVOID) loadLibAddr,// StartAddress
        (PVOID) dllPathAddr,// StartParameter (OPTIONAL)
        &hRemoteThread, // ThreadHandle
        &cid // ClientID
        );

    if (hRemoteThread == NULL) {
        return NULL;
    } else {
        return hRemoteThread;
    }
}
NTLIBAPI HANDLE create_remote_thread(HANDLE proc, void * func, void * param,DWORD* tid)
{
    HANDLE th = 0;
    *tid = 0;
    th = CreateRemoteThread(proc,0,0,(LPTHREAD_START_ROUTINE)func,param,0,tid);
    if (!th)
        th = RtlCreateUserThreadWrapper(proc,func,param);
    if (th)
        *tid = GetThreadId(th);
    return th;
}
NTLIBAPI unsigned long inject_me(unsigned long pid, wchar_t* dll) {
    if (pid == 0 || dll == 0 || dll[0] == 0) return 0; 
    HANDLE proc = OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE|PROCESS_CREATE_THREAD|PROCESS_QUERY_INFORMATION,0,pid);
    if (!proc ) {
        priv_access(SE_DEBUG_NAME,SE_PRIVILEGE_ENABLED,0);
        proc = OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE|PROCESS_CREATE_THREAD|PROCESS_QUERY_INFORMATION,0,pid);
    }
    if (!proc) return 0;

    wchar_t* target = (wchar_t*)VirtualAllocEx(proc,0,wcslen(dll)*sizeof(wchar_t),MEM_COMMIT,PAGE_READWRITE);
    if(!target) {CloseHandle(proc); return 0 ;}

    BOOL ret = WriteProcessMemory(proc,target,dll,wcslen(dll)*sizeof(wchar_t),0);
    if(!ret) {VirtualFreeEx(proc,target,0,MEM_RELEASE);CloseHandle(proc); return 0;}
    DWORD tid;
    HANDLE th = create_remote_thread(proc,GetProcAddress(GetModuleHandleA("kernel32.dll"),"LoadLibraryW"),target,&tid);
    if (!th) {VirtualFreeEx(proc,target,0,MEM_RELEASE);CloseHandle(proc); return 0;}
    DWORD code = 0;
    if (WAIT_OBJECT_0 == WaitForSingleObject(th,INFINITE) ){
        GetExitCodeThread(th,&code);
    }
    VirtualFreeEx(proc,target,0,MEM_RELEASE);
    CloseHandle(th);
    CloseHandle(proc);
    return code;
}
NTLIBAPI unsigned long call_remote(unsigned long pid, tproc_t p, void* par) {
    if( !pid || !p ) return 0;
    HANDLE proc = OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE|PROCESS_CREATE_THREAD|PROCESS_QUERY_INFORMATION,0,pid);
    if (!proc ) {
        priv_access(SE_DEBUG_NAME,SE_PRIVILEGE_ENABLED,0);
        proc = OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE|PROCESS_CREATE_THREAD|PROCESS_QUERY_INFORMATION,0,pid);
    }
    if (!proc) return 0;
    DWORD tid;
    DWORD code = 0;
    DWORD tmp;
    __try{
        DWORD cmp = *((DWORD*)p+1);
        if ( !ReadProcessMemory(proc,((DWORD*)p+1),&tmp,sizeof(tmp),0) || cmp != tmp) {
            CloseHandle(proc);
            return 0;
        }
        HANDLE th = create_remote_thread(proc,p,par,&tid);
        if (th && WAIT_OBJECT_0 == WaitForSingleObject(th,INFINITE) ) {
            GetExitCodeThread(th,&code);
            CloseHandle(th);
        }
    }
    __except(EXCEPTION_EXECUTE_HANDLER){}
    CloseHandle(proc);
    return code;
}
NTLIBAPI unsigned long call_remote_par(unsigned long pid, tproc_t p, void* par,size_t size,unsigned long* code){
    if( !pid || !p ) return 0;
    HANDLE proc = OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE|PROCESS_CREATE_THREAD|PROCESS_QUERY_INFORMATION,0,pid);
    if (!proc ) {
        priv_access(SE_DEBUG_NAME,SE_PRIVILEGE_ENABLED,0);
        proc = OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE|PROCESS_CREATE_THREAD|PROCESS_QUERY_INFORMATION,0,pid);
    }
    if (!proc) return 0;
    void* target = VirtualAllocEx(proc,0,size,MEM_COMMIT,PAGE_READWRITE);
    if(!target) {CloseHandle(proc); return 0 ;}

    BOOL ret = WriteProcessMemory(proc,target,par,size,0);
    if(!ret) {VirtualFreeEx(proc,target,0,MEM_RELEASE);CloseHandle(proc); return 0;}

    DWORD tid = 0;
    DWORD tmp;
    __try{
        DWORD cmp = *((DWORD*)p+1);
        if ( !ReadProcessMemory(proc,((DWORD*)p+1),&tmp,sizeof(tmp),0) || cmp != tmp) {
            VirtualFreeEx(proc,target,0,MEM_RELEASE);
            CloseHandle(proc);
            return 0;
        }
        HANDLE th = create_remote_thread(proc,p,target,&tid);
        if (th && WAIT_OBJECT_0 == WaitForSingleObject(th,INFINITE) ) {
            GetExitCodeThread(th,code);
            CloseHandle(th);
        }
    }
    __except(EXCEPTION_EXECUTE_HANDLER){}

    VirtualFreeEx(proc,target,0,MEM_RELEASE);
    CloseHandle(proc);
    return tid;
}

NTLIBAPI void * shared_section(size_t size, wchar_t * name, HANDLE& fm)
{
    using namespace ntdll;
    HANDLE dir;
    ntdll::UNICODE_STRING sess_dir_name;
    RtlInitUnicodeString(&sess_dir_name,L"\\Sessions\\BNOLINKS");
    OBJECT_ATTRIBUTES oa = {sizeof(oa),0,&sess_dir_name,OBJ_CASE_INSENSITIVE,0,0};

    if (0 ==  NtOpenDirectoryObject(&dir,DIRECTORY_QUERY|DIRECTORY_TRAVERSE,&oa))
    {
        ULONG rl = 0;
        ULONG context = 0;
        while (true)
        {
            auto stat = NtQueryDirectoryObject(dir,0,0,1,0,&context,&rl);
            if (!rl) break;
            void * buffer = _alloca(rl);
            stat = NtQueryDirectoryObject(dir,buffer,rl,1,0,&context,&rl);
            auto * obs = (OBJECT_DIRECTORY_INFORMATION*)buffer;
            if (!rl || !obs->Name.Buffer) break;
            extern int swprintf_s( wchar_t *buffer,size_t sizeOfBuffer,const wchar_t *format,...);
            size_t olen = wcslen(name) + obs->Name.Length + 64;
            wchar_t* sbuf = (wchar_t*)_alloca( sizeof(name[0]) * olen);
            swprintf_s(sbuf,olen,L"Session\\%s\\%s",obs->Name.Buffer,name);
            fm = OpenFileMapping(GENERIC_ALL,0,sbuf);
            if (fm)
                break;
        }
        CloseHandle(dir);
    }

    if (fm == 0)
    {
        SECURITY_DESCRIPTOR sd;
        InitializeSecurityDescriptor(&sd,SECURITY_DESCRIPTOR_REVISION);
        SetSecurityDescriptorDacl(&sd,true,0,0);
        SECURITY_ATTRIBUTES sa = {sizeof(sa),&sd};
#ifdef _AMD64_
        fm = CreateFileMapping(INVALID_HANDLE_VALUE,&sa,PAGE_EXECUTE_READWRITE, HIDWORD(size),LODWORD(size),name);
#else
        HANDLE fm = CreateFileMapping(INVALID_HANDLE_VALUE,&sa,PAGE_EXECUTE_READWRITE, 0,size,name);
#endif
    }
    if (fm)
    {
        return MapViewOfFileEx (fm,FILE_MAP_ALL_ACCESS,0,0,size,0);
    }
    return 0;
}

NTLIBAPI void release_section(void* p, HANDLE fm)
{
	UnmapViewOfFile(p);
	CloseHandle(fm);
}
NTLIBAPI
void *
    memmem (
    const void *haystack,
    size_t haystack_len,
    const void *needle,
    size_t needle_len)
{
    /* not really Rabin-Karp, just using additive hashing */
    char* haystack_ = (char*)haystack;
    char* needle_ = (char*)needle;
    int hash = 0;		/* this is the static hash value of the needle */
    int hay_hash = 0;	/* rolling hash over the haystack */
    char* last;
    size_t i;

    if (haystack_len < needle_len)
        return NULL;

    if (!needle_len)
        return haystack_;

    /* initialize hashes */
    for (i = needle_len; i; --i)
    {
        hash += *needle_++;
        hay_hash += *haystack_++;
    }

    /* iterate over the haystack */
    haystack_ = (char*)haystack;
    needle_ = (char*)needle;
    last = haystack_+(haystack_len - needle_len + 1);
    for (; haystack_ < last; ++haystack_)
    {
        if (hash == hay_hash &&
            *haystack_ == *needle_ &&	/* prevent calling memcmp, was a optimization from existing glibc */
            !memcmp (haystack_, needle_, needle_len))
            return haystack_;

        /* roll the hash */
        hay_hash -= *haystack_;
        hay_hash += *(haystack_+needle_len);
    }

    return NULL;
}

NTLIBAPI void debug_print(char* s,...)
{
    DWORD len = 0;
    va_list m;va_start (m,s);
    char a[256];
    extern int _vsnprintf(char *buffer,size_t count,const char *format,va_list argptr);
    _vsnprintf(a,sizeof(a),s,m);
    strcat(a,"\n");
    OutputDebugStringA(a);
    va_end(m);
}

NTLIBAPI void debug_printw(wchar_t* s,...)
{
    DWORD len = 0;
    va_list m;va_start (m,s);
    WCHAR a[256];
    extern int _vsnwprintf (wchar_t *string, size_t count, const wchar_t *format,va_list ap);
    _vsnwprintf(a,sizeof(a),s,m);
    wcscat(a,L"\n");
    OutputDebugStringW(a);
    va_end(m);
}


inline ULONG swap_long(ULONG l)
{
	return ((((l) >> 24) & 0x000000FFL ) |
		( ((l) >>  8) & 0x0000FF00L ) |  
		( ((l) <<  8) & 0x00FF0000L ) |  
		( ((l) << 24) & 0xFF000000L ) );

}
NTLIBAPI ULONG Inet_Addr(LPWSTR String, LPWSTR * Terminator = 0)
/*++

Routine Description:

    This function interprets the character string specified by the cp
    parameter.  This string represents a numeric Internet address
    expressed in the Internet standard ".'' notation.  The value
    returned is a number suitable for use as an Internet address.  All
    Internet addresses are returned in network order (bytes ordered from
    left to right).

    Internet Addresses

    Values specified using the "." notation take one of the following
    forms:

    a.b.c.d   a.b.c     a.b  a

    When four parts are specified, each is interpreted as a byte of data
    and assigned, from left to right, to the four bytes of an Internet
    address.  Note that when an Internet address is viewed as a 32-bit
    integer quantity on the Intel architecture, the bytes referred to
    above appear as "d.c.b.a''.  That is, the bytes on an Intel
    processor are ordered from right to left.

    Note: The following notations are only used by Berkeley, and nowhere
    else on the Internet.  In the interests of compatibility with their
    software, they are supported as specified.

    When a three part address is specified, the last part is interpreted
    as a 16-bit quantity and placed in the right most two bytes of the
    network address.  This makes the three part address format
    convenient for specifying Class B network addresses as
    "128.net.host''.

    When a two part address is specified, the last part is interpreted
    as a 24-bit quantity and placed in the right most three bytes of the
    network address.  This makes the two part address format convenient
    for specifying Class A network addresses as "net.host''.

    When only one part is given, the value is stored directly in the
    network address without any byte rearrangement.

Arguments:

    String - A character string representing a number expressed in the
        Internet standard "." notation.

    Terminator - Receives a pointer to the character that terminated
        the conversion.

Return Value:

    If no error occurs, inet_addr() returns an in_addr structure
    containing a suitable binary representation of the Internet address
    given.  Otherwise, it returns the value INADDR_NONE.

--*/

{
        ULONG val, base, n;
        WCHAR c;
        ULONG parts[4], *pp = parts;
		LPWSTR tmp;
		if (Terminator == 0)
		{
			Terminator = &tmp;
		}

again:
        /*
         * Collect number up to ``.''.
         * Values are specified as for C:
         * 0x=hex, 0=octal, other=decimal.
         */
        val = 0; base = 10;
        if (*String == L'0') {
                base = 8, String++;
                if (*String == L'x' || *String == L'X')
                        base = 16, String++;
        }

        while (c = *String) {
                if (iswdigit(c)) {
                        val = (val * base) + (c - L'0');
                        String++;
                        continue;
                }
                if (base == 16 && iswxdigit(c)) {
                        val = (val << 4) + (c + 10 - (islower(c) ? L'a' : L'A'));
                        String++;
                        continue;
                }
                break;
        }
        if (*String == L'.') {
                /*
                 * Internet format:
                 *      a.b.c.d
                 *      a.b.c   (with c treated as 16-bits)
                 *      a.b     (with b treated as 24 bits)
                 */
                /* GSS - next line was corrected on 8/5/89, was 'parts + 4' */
                if (pp >= parts + 3) {
                        *Terminator = String;
                        return ((ULONG) -1);
                }
                *pp++ = val, String++;
                goto again;
        }
        /*
         * Check for trailing characters.
         */
        if (*String && !iswspace(*String) && (*String != L':')) {
                *Terminator = String;
                return (INADDR_NONE);
        }
        *pp++ = val;
        /*
         * Concoct the address according to
         * the number of parts specified.
         */
        n = (ULONG)(pp - parts);
        switch ((int) n) {

        case 1:                         /* a -- 32 bits */
                val = parts[0];
                break;

        case 2:                         /* a.b -- 8.24 bits */
                if ((parts[0] > 0xff) || (parts[1] > 0xffffff)) {
                    *Terminator = String;
                    return(INADDR_NONE);
                }
                val = (parts[0] << 24) | (parts[1] & 0xffffff);
                break;

        case 3:                         /* a.b.c -- 8.8.16 bits */
                if ((parts[0] > 0xff) || (parts[1] > 0xff) ||
                    (parts[2] > 0xffff)) {
                    *Terminator = String;
                    return(INADDR_NONE);
                }
                val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) |
                        (parts[2] & 0xffff);
                break;

        case 4:                         /* a.b.c.d -- 8.8.8.8 bits */
                if ((parts[0] > 0xff) || (parts[1] > 0xff) ||
                    (parts[2] > 0xff) || (parts[3] > 0xff)) {
                    *Terminator = String;
                    return(INADDR_NONE);
                }
                val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) |
                      ((parts[2] & 0xff) << 8) | (parts[3] & 0xff);
                break;

        default:
                *Terminator = String;
                return (INADDR_NONE);
        }

        val = swap_long(val);
        *Terminator = String;
        return (val);
}

#ifdef __cplusplus
    }
}
#endif
#undef _CRT_SECURE_NO_WARNINGS